
#include "member_BWidget.h"
#include "member_BLayout.h"
#include "member_BSpacer.h"
#include "member_BSpring.h"

#include "ILayoutItem.h"

using namespace BWE;

ILayoutItem::ILayoutItem()
{
	align = Align_Center;
	finishWidth = true;
	finishHeight = true;
	stretch.setStretch(1.0f);
	dirty = true;
}
ILayoutItem::ILayoutItem(const ILayoutItem& other)
{
	finishWidth = other.finishWidth;
	finishHeight = other.finishHeight;
	widget = other.widget;
	layout = other.layout;
	spring = other.spring;
	align = other.align;
	stretch = other.stretch;
	policy = other.policy;
	dirty = true;
}
ILayoutItem::~ILayoutItem()
{
	clear();
}

void ILayoutItem::clear()
{
	if (widget)
	{
		widget_member(widget)->upperLayout = 0;
		widget = 0;
	}
	else if (layout)
	{
		layout_member(layout)->parent = 0;
		layout = 0;
	}
	else if (spacer)
	{
		spacer_member(spacer)->layout = 0;
		layout = 0;
	}
	else if (spring)
	{
		spring_member(spring)->layout = 0;
		spring = 0;
	}
	this->dirty = true;
}
bool ILayoutItem::empty() const
{
	return !widget && !layout && !spacer && !spring;
}
void ILayoutItem::flush()
{
	if (dirty)
	{
		dirty = false;
		ignored = true;
		if (widget)
			ignored = !widget->visible();
		else if (layout)
			ignored = !layout->visible();
		else if (spacer)
			ignored = !spacer->enabled();
		else if (spring)
			ignored = !spring->enabled();

		if (widget)
		{
			size = widget->size();
			minSize = widget->minSize();
			maxSize = widget->maxSize();
			sizeHint = widget->sizeHint();
			fixedSize = widget->fixedSize();
			sizePolicy = widget->sizePolicy();
		}
		else if (layout)
		{
			size = layout->baseSize();
			minSize = layout->minSize();
			maxSize = layout->maxSize();
			sizeHint = layout->sizeHint();
			fixedSize = layout->fixedSize();
			sizePolicy = layout->sizePolicy();
		}
		else if (spacer)
		{
			size = spacer->rect().size();
			minSize = spacer->minSize();
			maxSize = spacer->maxSize();
			sizeHint = spacer->sizeHint();
			fixedSize = spacer->fixedSize();
			sizePolicy = spacer->sizePolicy();
		}
		else if (spring)
		{
			size = spring->rect().size();
			minSize = spring->minSize();
			maxSize = spring->maxSize();
			sizeHint = spring->sizeHint();
			fixedSize = spring->sizeHint();
			sizePolicy = spring->sizePolicy();
		}
		if (ignored)
		{
			size.reset();
			minSize.reset();
			maxSize.set(999999, 999999);
			sizeHint.reset();
			fixedSize.reset();
			sizePolicy.reset();
		}
		sizeHint.limit(minSize, maxSize);

		baseSize.reset();
		if (sizePolicy.widthPolicy() & Policy_Fixed)
			baseSize.width() = bMax(baseSize.width(), fixedSize.width());
		if (sizePolicy.widthPolicy() & Policy_Preferred)
			baseSize.width() = bMax(baseSize.width(), sizeHint.width());
		if (sizePolicy.heightPolicy() & Policy_Fixed)
			baseSize.height() = bMax(baseSize.height(), fixedSize.height());
		if (sizePolicy.heightPolicy() & Policy_Preferred)
			baseSize.height() = bMax(baseSize.height(), sizeHint.height());

		if (!(sizePolicy.widthPolicy() & Policy_Expanding) && maxSize.width() > baseSize.width())
			maxSize.width() = baseSize.width();
		if (!(sizePolicy.widthPolicy() & Policy_Shrinking) && minSize.width() < baseSize.width())
			minSize.width() = baseSize.width();
		if (!(sizePolicy.heightPolicy() & Policy_Expanding) && maxSize.height() > baseSize.height())
			maxSize.height() = baseSize.height();
		if (!(sizePolicy.heightPolicy() & Policy_Shrinking) && minSize.height() < baseSize.height())
			minSize.height() = baseSize.height();

		preferSize = baseSize;
		preferSize.limit(minSize, maxSize);

		if (policy.widthPolicy())
			sizePolicy.widthPolicy() = policy.widthPolicy();
		if (policy.heightPolicy())
			sizePolicy.heightPolicy() = policy.heightPolicy();

	}
}

bool ILayoutItem::prepare()
{
	if (dirty)
		this->flush();

	if (ignored)
	{
		finishHeight = true;
		finishWidth = true;
		return false;
	}

	finishHeight = false;
	finishWidth = false;
	realSize.set(0, 0);

	if (sizePolicy.widthPolicy() == Policy_None)
	{
		finishWidth = true;
		realSize.width() = size.width();
	}
	else if (sizePolicy.widthPolicy() == Policy_Fixed)
	{
		finishWidth = true;
		realSize.width() = fixedSize.width();
	}
	else if (sizePolicy.widthPolicy() == Policy_Preferred)
	{
		finishWidth = true;
		realSize.width() = sizeHint.width();
	}
	else if (sizePolicy.widthPolicy() & Policy_Preferred)
	{
		realSize.width() = sizeHint.width();
	}

	if (sizePolicy.heightPolicy() == Policy_None)
	{
		finishHeight = true;
		realSize.height() = size.height();
	}
	else if (sizePolicy.heightPolicy() == Policy_Fixed)
	{
		finishHeight = true;
		realSize.height() = fixedSize.height();
	}
	else if (sizePolicy.heightPolicy() == Policy_Preferred)
	{
		finishHeight = true;
		realSize.height() = sizeHint.height();
	}
	else if (sizePolicy.heightPolicy() & Policy_Preferred)
	{
		realSize.height() = sizeHint.height();
	}

	realSize.limit(minSize, maxSize);
	return true;
}
bool ILayoutItem::prepare(int remain, int width, int height)
{
	if (dirty)
		this->flush();

	realSize = size;
	if (width > 0)
		realSize.width() = width;
	if (height > 0)
		realSize.height() = height;

	if (ignored)
	{
		finishHeight = true;
		finishWidth = true;
		return false;
	}
	if (this->spring && remain < 0)
	{
		finishHeight = true;
		finishWidth = true;
		return false;
	}

	finishHeight = false;
	finishWidth = false;
	realSize.set(width, height);

	if (sizePolicy.widthPolicy() == Policy_Fixed)
	{
		finishWidth = true;
		realSize.width() = fixedSize.width();
	}
	else if (sizePolicy.widthPolicy() == Policy_Preferred)
	{
		finishWidth = true;
		realSize.width() = sizeHint.width();
	}
	else
	{
		if (sizePolicy.widthPolicy() & Policy_Fixed)
		{
			if (realSize.width() < fixedSize.width())
				realSize.width() = fixedSize.width();
		}
		if (sizePolicy.widthPolicy() & Policy_Preferred)
		{
			if (realSize.width() < sizeHint.width())
				realSize.width() = sizeHint.width();
		}
	}

	if (sizePolicy.heightPolicy() == Policy_Fixed)
	{
		finishHeight = true;
		realSize.height() = fixedSize.height();
	}
	else if (sizePolicy.heightPolicy() == Policy_Preferred)
	{
		finishHeight = true;
		realSize.height() = sizeHint.height();
	}
	else
	{
		if (sizePolicy.heightPolicy() & Policy_Fixed)
		{
			if (realSize.height() < fixedSize.height())
				realSize.height() = fixedSize.height();
		}
		if (sizePolicy.heightPolicy() & Policy_Preferred)
		{
			if (realSize.height() < sizeHint.height())
				realSize.height() = sizeHint.height();
		}
	}

	if (!finishWidth || !finishHeight)
	{
		if (stretch.widthStretch() == 0.0f)
			finishWidth = true;
		if (stretch.heightStretch() == 0.0f)
			finishHeight = true;
	}
	realSize.limit(minSize, maxSize);
	baseSize = realSize;
	if (!finishWidth && width > 0)
	{
		if (realSize.width() > width && sizePolicy.widthPolicy() & Policy_Shrinking)
			realSize.width() = width;
		if (realSize.width() < width && sizePolicy.widthPolicy() & Policy_Expanding)
			realSize.width() = width;
	}
	if (!finishHeight && height > 0)
	{
		if (realSize.height() > height && sizePolicy.heightPolicy() & Policy_Shrinking)
			realSize.height() = height;
		if (realSize.height() < height && sizePolicy.heightPolicy() & Policy_Expanding)
			realSize.height() = height;
	}
	realSize.limit(minSize, maxSize);
	return true;
}
void ILayoutItem::move(int x, int y)
{
	rect.setPos(x, y);
	realRect.set(rect.pos(), realSize);
	if (widget)
	{
		widget->setRect(realRect);
	}
	else if (layout)
	{
		layout->setRect(realRect);
		layout->adjust();
	}
	else if (spacer)
	{
		spacer->setRect(realRect);
	}
	else if (spring)
	{
		spring->setRect(realRect);
	}
}
void ILayoutItem::adjust(int x, int y, int w, int h)
{
	rect.set(x, y, w, h);
	realRect = rect.align(align, realSize);
	if (widget)
	{
		widget->setRect(realRect);
	}
	else if (layout)
	{
		layout->setRect(realRect);
		layout->adjust();
	}
	else if (spacer)
	{
		spacer->setRect(realRect);
	}
	else if (spring)
	{
		spring->setRect(realRect);
	}
}
void ILayoutItem::adjust(const BRect& rect)
{
	this->rect = rect;
	realRect = rect.align(align, realSize);
	if (widget)
	{
		widget->setRect(realRect);
	}
	else if (layout)
	{
		layout->setRect(realRect);
		layout->adjust();
	}
	else if (spacer)
	{
		spacer->setRect(realRect);
	}
	else if (spring)
	{
		spring->setRect(realRect);
	}
}

void ILayoutItem::operator = (BWidget* widget)
{
	this->widget = widget;
	this->layout = 0;
	this->spacer = 0;
	this->spring = 0;
	this->dirty = true;
}
void ILayoutItem::operator = (BLayout* layout)
{
	this->widget = 0;
	this->layout = layout;
	this->spacer = 0;
	this->spring = 0;
	this->dirty = true;
}
void ILayoutItem::operator = (BSpacer* spacer)
{
	this->widget = 0;
	this->layout = 0;
	this->spacer = spacer;
	this->spring = 0;
	this->dirty = true;
}
void ILayoutItem::operator = (BSpring* spring)
{
	this->widget = 0;
	this->layout = 0;
	this->spacer = 0;
	this->spring = spring;
	this->dirty = true;
}

bool ILayoutItem::operator == (const ILayoutItem& other) const
{
	if (this == &other)
		return true;
	return widget == other.widget && layout == other.layout && spacer == other.spacer && spring == other.spring;
}
bool ILayoutItem::operator == (const BObject* object) const
{
	if (widget)
		return widget == object;
	if (layout)
		return layout == object;
	if (spacer)
		return spacer == object;
	if (spring)
		return spring == object;
	return object == 0;
}
bool ILayoutItem::operator == (const BWidget* widget) const
{
	return this->widget == widget;
}
bool ILayoutItem::operator == (const BLayout* layout) const
{
	return this->layout == layout;
}
bool ILayoutItem::operator == (const BSpacer* spacer) const
{
	return this->spacer == spacer;
}
bool ILayoutItem::operator == (const BSpring* spring) const
{
	return this->spring == spring;
}

bool ILayoutItem::operator != (const ILayoutItem& other) const
{
	if (this == &other)
		return false;
	return widget != other.widget || layout != other.layout || spacer != other.spacer || spring != other.spring;
}
bool ILayoutItem::operator != (const BObject* object) const
{
	if (widget)
		return widget != object;
	if (layout)
		return layout != object;
	if (spacer)
		return spacer != object;
	if (spring)
		return spring != object;
	return object != 0;
}
bool ILayoutItem::operator != (const BWidget* widget) const
{
	return this->widget != widget;
}
bool ILayoutItem::operator != (const BLayout* layout) const
{
	return this->layout != layout;
}
bool ILayoutItem::operator != (const BSpacer* spacer) const
{
	return this->spacer != spacer;
}
bool ILayoutItem::operator != (const BSpring* spring) const
{
	return this->spring != spring;
}
